/*
 * Copyright 2013 Alan Burlison, alan@bleaklow.com.  All rights reserved.
 * Use is subject to license terms.  See LICENSE.txt for details.
 */

/*
 * SPI Master definitions and class.
 */

#ifndef SPIMaster_h
#define SPIMaster_h

#include <avr/io.h>
#include "utils.h"

#define SPI_MODE_0 (0x00)
#define SPI_MODE_1 (BIT(CPHA))
#define SPI_MODE_2 (BIT(CPOL))
#define SPI_MODE_3 (BIT(CPOL) | BIT(CPHA))

/*
 * SPI master.
 */
class SPIMaster {
public:
    /*
     * Create a new SPI master.
     * _spcr - SPI control register value.
     * _spsr - SPI status register value.
     * _csn  - Chip Select Not pin.
     */
    SPIMaster(uint8_t _spcr, uint8_t _spsr, const pin_t *const _csn);

    /*
     * Initialise the SPI pins for use.
     * initSharedPins - if true, initialise the shared pins,
     *                  if false, just the pins for this master.
     */
    virtual void SPIInitPins(bool shared);

    /*
     * Set the SPI mode.
     */
    inline void SPISetMode() __attribute__ ((__always_inline__))
      { SPCR = spcr; SPSR = spsr; }

    /*
     * Select the device.
     */
    inline void SPISelect() __attribute__ ((__always_inline__))
      { SET_BIT_LO(*csn->port, csn->bit); }

    /*
     * Write & read a byte to/from the SPI interface.
     * value - the value to write.
     * return - the value that has been read.
     */
    inline uint8_t SPIWriteRead(uint8_t value) __attribute__ ((__always_inline__))
      { SPDR = value; SPIWait(); return SPDR; }

    /*
     * Wait for the current SPI transaction to complete.
     */
    inline void SPIWait() __attribute__ ((__always_inline__))
      { while (! (SPSR & BIT(SPIF))); }

    /*
     * Deselect the device.
     */
    inline void SPIDeselect() __attribute__ ((__always_inline__))
      { SET_BIT_HI(*csn->port, csn->bit); }

protected:
    const uint8_t spcr;         // SPI control register.
    const uint8_t spsr;         // SPI status register.
    const pin_t *const csn;     // Chip Select Not port.
};

#endif
